﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace M3U8下载神器
{

    public partial class DownloadForm : Form
    {
        SynchronizationContext context;
        CancellationTokenSource source = new CancellationTokenSource();
        public M3U8Package Package { private set; get; }

        public int TaskSize { set; get; } = 8;

        public List<Task> Tasks = new List<Task>();

        public Action FinishAction { set; get; }

        public DownloadForm()
        {
            InitializeComponent();
            context = SynchronizationContext.Current;
            FormClosing += (o, e) =>
            {
                if (Package != null && !Package.AllFinish())
                {
                    if (MessageBox.Show("正在下载，确定要终止下载并退出?", "选择", MessageBoxButtons.OKCancel) != DialogResult.OK)
                    {
                        //Package = null;
                        e.Cancel = true;
                    }
                }
            };
            FormClosed += (o, e) =>
            {
                Task.WaitAll(Tasks.ToArray());
                source.Cancel();
                source.Dispose();
            };
        }
        public void Build(M3U8Package package)
        {
            Package = package;//package have began
            textBox_title.Text = Path.GetFileName(package.SavePath);
            Text = textBox_title.Text;
            textBox_address.Text = package.Src;
        }
        private void RebuildWord()
        {
            foreach (var ts in Package.AllTsInfos)
            {
                if (!ts.Finish)
                {
                    Package.WorkTsInfos.Enqueue(ts);
                }
            }
        }
        public bool CheckAll(bool reset=false)
        {
            bool flag = true;
            for (int i = 0; i < Package.Count; i++)
            {
                var file = Package.Gid + "\\" + i + ".ts";
                var fi = new FileInfo(file);
                flag &= fi.Exists;
                if (reset)
                {
                    Package.AllTsInfos[i].Finish = fi.Exists;
                }
            }
            return flag;
        }
        public void OnCompleted(Task task)
        {
            Tasks.Remove(task);
            UpdateUI();
            if (Package.AllFinish()&&CheckAll(true))
            {
                lock (Package.LockObject)
                {
                    try
                    {
                        if (!Package.Finish)
                        {
                            Debug.WriteLine(this.Text + ":下载完成");

                            
                            var dest = Package.SavePath;
                            var temp = dest + ".tmp";

                            var destFi = new FileInfo(dest);
                            if (destFi.Exists)
                            {
                                destFi.Delete();
                            }
                            using (var output = File.Create(temp))
                            {
                                for (int i = 0; i < Package.Count; i++)
                                {
                                    var file = Package.Gid + "\\" + i + ".ts";
                                    using (var ts = File.OpenRead(file))
                                    {
                                        ts.CopyTo(output);
                                    }
                                }
                            }
                            new FileInfo(temp).MoveTo(dest);//重命名回目标文件名
                            Package.Finish = true;
                            Thread.Sleep(1000);
                            FinishAction?.Invoke();
                            this.Close();
                        }
                    }
                    catch(IOException ioe)
                    {
                        textBox_msg.Text = ("读写文件异常,请重新下载!--" + ioe.Message);
                    }
                    catch (Exception e)
                    {
                        
                    }
                }
            }
            else
            {
                Debug.WriteLine(this.Text + ":还有部分未下载完成");
            }
        }
        public void UpdateUI()
        {
            context.Post((o) =>
            {
                try
                {
                    string msg = $"完成：{Package.FinishCount}/{Package.Count}，正在连接数：{Tasks.Count}";
                    label_finish.Text = msg;
                }
                catch (Exception)
                {
                }
            }, null);
        }
        public void Start()
        {
            UpdateUI();
            TsDownloader downloader = new TsDownloader(Package.Gid);
            for (; Tasks.Count < TaskSize;)
            {
                var t = Task.Factory.StartNew(() =>
                  {
                      using (var httpClient = new WebClient() { BaseAddress = Package.Host })
                      {
                          httpClient.Headers.Add("User-Agent",//
                              "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36");
                          while (!source.Token.IsCancellationRequested)
                          {

                              var ts = Package.WorkTsInfos.TryDequeue();
                              if (ts != null)
                              {
                                  lock (ts.LockObject)
                                  {
                                      try
                                      {
                                          if (!ts.Finish)
                                          {
                                              downloader.Download(httpClient, ts, out var ex);
                                              if (!string.IsNullOrEmpty(ex))
                                              {
                                                  Debug.WriteLine(this.Text + ':' + ex);
                                              }
                                          }
                                      }
                                      catch (Exception)
                                      {
                                      }
                                  }
                                  UpdateUI();
                              }
                              else
                              {
                                  break;
                              }
                          }
                      }
                  }, source.Token);
                Tasks.Add(t);
                t.GetAwaiter().OnCompleted(() => OnCompleted(t));
            }
        }
        public void RefreshDownload()
        {
            if (Tasks.Count == 0)
            {
                RebuildWord();
            }
            Start();
            Thread.Sleep(1000);
        }
        private void button1_Click(object sender, EventArgs e)
        {
            RefreshDownload();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.Filter = "M3u8List|*.m3ul";
            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                Package.Export(out var data, saveFileDialog.FileName);
            }
        }

        private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            Package.Export(out var data);
            new TextForm() { ShowText = data }.Show();
        }
    }
}
